/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package org.springblade.modules.repair.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.mp.base.BaseServiceImpl;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.modules.repair.dto.defert.PlanAndSignDateDTO;
import org.springblade.modules.repair.entity.MaintainMalfunctionLog;
import org.springblade.modules.repair.entity.MaintainPlanContent;
import org.springblade.modules.repair.entity.MaintainPlanContentExt;
import org.springblade.modules.repair.entity.MaintainPlanDefertHistory;
import org.springblade.modules.repair.mapper.MaintainPlanDefertHistoryMapper;
import org.springblade.modules.repair.service.*;
import org.springblade.modules.repair.vo.MaintainPlanDefertHistoryVO;
import org.springblade.modules.repair.vo.defert.DefertSaveVo;
import org.springblade.modules.repair.vo.defert.MalfunctionLogExtVo;
import org.springblade.modules.repair.vo.defert.PlanAndSignDateVo;
import org.springblade.modules.repair.vo.defert.PlanConfigVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 维保任务延期历史日志 服务实现类
 *
 * @author ysq
 * @since 2022-11-19
 */
@Service
public class MaintainPlanDefertHistoryServiceImpl extends BaseServiceImpl<MaintainPlanDefertHistoryMapper, MaintainPlanDefertHistory> implements IMaintainPlanDefertHistoryService {


	@Autowired
	private IMaintainPlanContentExtService maintainPlanContentExtService;

	@Autowired
	private IMaintainMalfunctionLogService maintainMalfunctionLogService;

	@Autowired
	private IMaintainPlanContentService maintainPlanContentService;

	@Autowired
	private MaintainPlanConfigService maintainPlanConfigService;

	/**
	 * 1:非年审，2:年审
	 */
	private final static Integer[] AUDIT_TYPES = {0, 1, 2};

	/**
	 * 0:初始化 1:提前 2:延后，3：普通延期 4：特殊
	 */
	private final static Integer[] DEFERT_TYPE = {0, 1, 2, 3, 4};

	/**
	 * 最终延期类型
	 * 1：已延期，
	 * 2：已提前
	 * 3: 无变化
	 * 4: 从未调整 -默认状态
	 * 5：特殊延期
	 */
	private final static Integer[] PLAN_DEFERT_TYPE = {0, 1, 2, 3, 4, 5};

	@Override
	public IPage<MaintainPlanDefertHistoryVO> selectMaintainPlanDefertHistoryPage(IPage<MaintainPlanDefertHistoryVO> page, MaintainPlanDefertHistoryVO maintainPlanDefertHistory) {
		return page.setRecords(baseMapper.selectMaintainPlanDefertHistoryPage(page, maintainPlanDefertHistory));
	}


	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean save(DefertSaveVo defertSaveVo) {

		MaintainPlanContent maintainPlanContent = maintainPlanContentService.getById(defertSaveVo.getPlanId());
		final String yyyyMMdd1 = DateUtil.format(defertSaveVo.getOldPlanDate(), "yyyyMMdd");
		final String yyyyMMdd2 = DateUtil.format(maintainPlanContent.getPlanDate(), "yyyyMMdd");
		if (!yyyyMMdd1.equals(yyyyMMdd2)) {
			throw new ServiceException("日期调整失败该任务已被执行");
		}
		final String userName = AuthUtil.getNickName();
		//每次逾期都是针对上一次操作,按照时间倒序获取最后一条修改即可
		List<MaintainPlanDefertHistory> list = this.list(Wrappers.<MaintainPlanDefertHistory>lambdaQuery().eq(MaintainPlanDefertHistory::getPlanId, defertSaveVo.getPlanId()).orderByDesc(MaintainPlanDefertHistory::getCreateTime));
		//如果为空说明是历史数据，插入一条初始化数据
		if (list.size() == 0) {
			MaintainPlanDefertHistory maintainPlanDefertHistory = new MaintainPlanDefertHistory();
			maintainPlanDefertHistory.setPlanId(maintainPlanContent.getId());
			maintainPlanDefertHistory.setPlanDate(maintainPlanContent.getPlanDate());
			PlanConfigVo planConfigVo = maintainPlanConfigService.getPlanConfigVo(maintainPlanContent.getElevatorId());
			BeanUtils.copyProperties(planConfigVo, maintainPlanDefertHistory);
			maintainPlanDefertHistory.setPlanType(planConfigVo.getAuditType());
			maintainPlanDefertHistory.setCreateUserName(userName);
			maintainPlanDefertHistory.setDefertType(DEFERT_TYPE[0]);
			maintainPlanDefertHistory.setDefertDays(0);
			maintainPlanDefertHistory.setDefertPlanDays(0);
			this.save(maintainPlanDefertHistory);
			list.add(maintainPlanDefertHistory);
		}
		MaintainPlanDefertHistory maintainPlanDefertHistory = list.get(0);
		final Integer auditType = maintainPlanDefertHistory.getPlanType();
		MaintainPlanContentExt maintainPlanContentExt = maintainPlanContentExtService.getOne(Wrappers.<MaintainPlanContentExt>lambdaQuery().eq(MaintainPlanContentExt::getPlanId, defertSaveVo.getPlanId()));

		//需要更改的时间
		Date planDate = defertSaveVo.getPlanDate();

		//上一次的时间,如果上次为null取工单的排期时间
		Date defertPlanDate = maintainPlanDefertHistory.getDefertPlanDate() == null ? maintainPlanDefertHistory.getPlanDate() : maintainPlanDefertHistory.getDefertPlanDate();
		//本地更新获取时间差
		int nowDay = Convert.toInt(DateUtil.betweenDay(planDate, defertPlanDate, true));

		//原有的时间
		int historyDay = Convert.toInt(DateUtil.betweenDay(maintainPlanDefertHistory.getPlanDate(), planDate, true));

		MaintainPlanDefertHistory saveModel = new MaintainPlanDefertHistory();
		BeanUtil.copyProperties(maintainPlanDefertHistory, saveModel);
		saveModel.setId(null);
		saveModel.setDefertPlanDate(defertSaveVo.getPlanDate());
		saveModel.setDefertDays(nowDay);
		saveModel.setDefertPlanDays(historyDay);
		saveModel.setDefertDesc(defertSaveVo.getDefertDesc());
		saveModel.setDefertImg(defertSaveVo.getDefertImg());
		saveModel.setCreateUserName(userName);

		/**
		 * 提前的时候需要校验年审非年审的逻辑
		 */
		//当前时间
		Date nowDate = new Date();
		final Integer nowDateInt = Convert.toInt(DateUtil.format(nowDate, "yyyyMMdd"));

		//要修改的时间
		Date updateDate = defertSaveVo.getPlanDate();
		final Integer updateDateInt = Convert.toInt(DateUtil.format(updateDate, "yyyyMMdd"));

		//第一次排期时间
		Date planDate2 = maintainPlanDefertHistory.getPlanDate();
		final Integer planDate2Int = Convert.toInt(DateUtil.format(planDate2, "yyyyMMdd"));

		//延后的判断
		if (defertPlanDate.getTime() < planDate.getTime()) {
			if (nowDay == 1) {
				if (auditType.equals(AUDIT_TYPES[1])) {
					saveModel.setDefertType(DEFERT_TYPE[2]);
					maintainPlanContentExt.setDeferType(PLAN_DEFERT_TYPE[1]);
				} else {
					//年审总体延期1天设置为延期状态大于1天设置特殊延期状态
					if (historyDay == 1) {
						maintainPlanContentExt.setDeferType(PLAN_DEFERT_TYPE[1]);
						saveModel.setDefertType(DEFERT_TYPE[3]);
					} else if (historyDay > 1) {
						maintainPlanContentExt.setDeferType(PLAN_DEFERT_TYPE[5]);
						saveModel.setDefertType(DEFERT_TYPE[4]);
					}
				}

			} else if (nowDay >= 2) {
				//大于两天需要判断是否非年审更新延后,年审梯更新为特殊延期
				if (auditType.equals(AUDIT_TYPES[1])) {
					if (planDate2Int > updateDateInt) {
						saveModel.setDefertType(DEFERT_TYPE[1]);
						maintainPlanContentExt.setDeferType(PLAN_DEFERT_TYPE[2]);
					} else {
						maintainPlanContentExt.setDeferType(PLAN_DEFERT_TYPE[1]);
						saveModel.setDefertType(DEFERT_TYPE[2]);
					}
				} else {
					saveModel.setDefertType(DEFERT_TYPE[4]);
					maintainPlanContentExt.setDeferType(PLAN_DEFERT_TYPE[5]);
				}
			}
		} else {
			/**
			 * 非年审提前只能提前到今日
			 */
			if (auditType.equals(AUDIT_TYPES[1])) {

				if (updateDateInt < nowDateInt) {
					throw new ServiceException("非年审电梯提前时间不能小于今日");
				}
				//非年审提前大于1天都是延后
				if (historyDay > 0) {
					if (planDate2Int > updateDateInt) {
						maintainPlanContentExt.setDeferType(PLAN_DEFERT_TYPE[2]);
					} else {
						maintainPlanContentExt.setDeferType(PLAN_DEFERT_TYPE[1]);
					}
				}

			} else {
				if (updateDateInt < planDate2Int) {
					throw new ServiceException("年审电梯提前时间不能小于第一次排期时间" + DateUtil.format(planDate2, "yyyy-MM-dd"));
				}

				//年审总体延期1天设置为延期状态大于1天设置特殊延期状态
				if (historyDay == 1) {
					maintainPlanContentExt.setDeferType(PLAN_DEFERT_TYPE[1]);
				} else if (historyDay > 1) {
					maintainPlanContentExt.setDeferType(PLAN_DEFERT_TYPE[5]);
				}
			}
			saveModel.setDefertType(DEFERT_TYPE[1]);

		}

		if (historyDay == 0) {
			//无变化
			int defertType = 3;
			maintainPlanContentExt.setDeferType(defertType);
		}

		//保存日志
		this.save(saveModel);
		maintainPlanContentExt.setDeferWarrant(2);
		maintainPlanContentExt.setDeferCounts(Convert.toInt(maintainPlanContentExt.getDeferCounts(), 0) + 1);
		maintainPlanContentExt.setDeferDescCounts(Convert.toInt(maintainPlanContentExt.getDeferDescCounts(), 0) + 1);
		//更新总状态
		maintainPlanContentExtService.updateById(maintainPlanContentExt);


		//任务进度条信息
		final List<MaintainMalfunctionLog> malfunctionLogList = maintainMalfunctionLogService.list(Wrappers.<MaintainMalfunctionLog>lambdaQuery().eq(MaintainMalfunctionLog::getPlanId, defertSaveVo.getPlanId()).orderByDesc(MaintainMalfunctionLog::getCreateTime));
		final int size = malfunctionLogList.size();
		if (size == 1) {
			MaintainMalfunctionLog maintainMalfunctionLog = new MaintainMalfunctionLog();
			maintainMalfunctionLog.setPlanId(defertSaveVo.getPlanId());
			maintainMalfunctionLog.setTypeName("调整计划时间");
			maintainMalfunctionLog.setExecutor(userName);
			MalfunctionLogExtVo malfunctionLogExtVo = new MalfunctionLogExtVo();
			malfunctionLogExtVo.setDesc("最终调整计划日期至");
			malfunctionLogExtVo.setPlanDate(DateUtil.format(defertSaveVo.getPlanDate(), "yyyy/MM/dd"));
			maintainMalfunctionLog.setExt(JSON.toJSONString(malfunctionLogExtVo));
			maintainMalfunctionLog.setPlanStatus(1);
			maintainMalfunctionLogService.save(maintainMalfunctionLog);
		} else {
			final MaintainMalfunctionLog maintainMalfunctionLog = malfunctionLogList.get(0);
			maintainMalfunctionLog.setExecutor(userName);
			maintainMalfunctionLog.setTypeName("调整计划时间");
			MalfunctionLogExtVo malfunctionLogExtVo = new MalfunctionLogExtVo();
			malfunctionLogExtVo.setDesc("最终调整计划日期至");
			malfunctionLogExtVo.setPlanDate(DateUtil.format(defertSaveVo.getPlanDate(), "yyyy/MM/dd"));
			maintainMalfunctionLog.setExt(JSON.toJSONString(malfunctionLogExtVo));
			maintainMalfunctionLogService.updateById(maintainMalfunctionLog);
		}


		maintainPlanContent.setPlanDate(defertSaveVo.getPlanDate());
		maintainPlanContentService.updateById(maintainPlanContent);
		return true;
	}

	@Override
	public List<PlanAndSignDateVo> getPlanAndSignDates(PlanAndSignDateDTO planAndSignDateDTO) {


		/**
		 * 0:表示非当前计划1:表示初始计划 2:表示当前计划
		 */
		Integer[] historyPlan = {0, 1, 2};

		//表示日期可选
		Integer selectType = 1;

		//1:提前保养2:表示延后
		Integer type = 1;

		MaintainPlanContent maintainPlanContent = maintainPlanContentService.getById(planAndSignDateDTO.getPlanId());
		int planDate = Convert.toInt(DateUtil.format(maintainPlanContent.getPlanDate(), "yyyyMMdd"));
		planAndSignDateDTO.setElevatorId(maintainPlanContent.getElevatorId());
		String endYearDate = DateUtil.format(DateUtil.endOfYear(new Date()), "yyyyMMdd");
		List<PlanAndSignDateVo> planAndSignDates;
		if (planAndSignDateDTO.getBeginTime() > Convert.toInt(endYearDate)) {
			planAndSignDates = this.getNextYear(planAndSignDateDTO);
		} else {
			planAndSignDates = baseMapper.getPlanAndSignDates(planAndSignDateDTO);
		}
		List<MaintainPlanDefertHistory> historyList = this.list(Wrappers.<MaintainPlanDefertHistory>lambdaQuery().eq(MaintainPlanDefertHistory::getPlanId, planAndSignDateDTO.getPlanId()).orderByDesc(MaintainPlanDefertHistory::getCreateTime));
		if (historyList.size() == 0) {
			throw new ServiceException("此工单不存在延期的初始化数据请联系管理员");
		}
		PlanConfigVo planConfigVo = maintainPlanConfigService.getPlanConfigVo(maintainPlanContent.getElevatorId());
		Integer auditType = planConfigVo.getAuditType();
		int nowDate = Convert.toInt(DateUtil.format(new Date(), "yyyyMMdd"));

		for (PlanAndSignDateVo planAndSignDateVo : planAndSignDates) {
			planAndSignDateVo.setPlanTypeNames(planAndSignDateVo.getPlanTypeName());
			//签到时间
			final String yyyyMMdd1 = DateUtil.format(planAndSignDateVo.getSignDate(), "yyyyMMdd");
			final MaintainPlanDefertHistory maintainPlanDefertHistory = historyList.get(0);
			final Integer defertPlanDays = maintainPlanDefertHistory.getDefertPlanDays();
			//工单第一次排期的时间
			final String yyyyMMdd2 = DateUtil.format(maintainPlanDefertHistory.getPlanDate(), "yyyyMMdd");
			//最后一次调整时间和初始化时间差不等0,表示日期变动过,并且和日历相等
			if (yyyyMMdd1.equals(yyyyMMdd2)) {
				planAndSignDateVo.setHistoryPlan(historyPlan[1]);
			}
			//判断是否存在初始数据(延期记录大于1表示调整过)
			if (historyList.size() > 1) {
				String yyyyMMdd3 = DateUtil.format(maintainPlanDefertHistory.getDefertPlanDate(), "yyyyMMdd");
				if (defertPlanDays != 0 && yyyyMMdd1.equals(yyyyMMdd3)) {
					planAndSignDateVo.setHistoryPlan(historyPlan[2]);
				} else if (defertPlanDays == 0 && yyyyMMdd1.equals(yyyyMMdd2)) {
					planAndSignDateVo.setHistoryPlan(historyPlan[1]);
				}
				if (auditType.equals(AUDIT_TYPES[1])) {
					//判断非年审,
					final Integer signDate = Convert.toInt(yyyyMMdd1);
					if (planAndSignDateDTO.getType().equals(type)) {
						//当前时间小于签到时间，并且签到时间小于最后一次排期时间=提前时间段
						if (nowDate <= signDate && signDate <= Convert.toInt(yyyyMMdd3)) {
							planAndSignDateVo.setIsSelect(selectType);
						}
					} else {
						//最后一次排期时间小于签到时间=延后的时间段
						if (Convert.toInt(yyyyMMdd3) <= signDate) {
							planAndSignDateVo.setIsSelect(selectType);
						}
					}

				} else {
					//判断年审
					final Integer signDate = Convert.toInt(yyyyMMdd1);
					final Integer yyyyMMdd = Convert.toInt(yyyyMMdd2);

					if (planAndSignDateDTO.getType().equals(type)) {
						//如果签到时间大于第一次排期时间并且签到时间小于最后一次的排期时间,表示可以提前的时间段
						if (signDate >= yyyyMMdd && signDate < Convert.toInt(yyyyMMdd3) && signDate >= nowDate) {
							planAndSignDateVo.setIsSelect(selectType);
						}
					} else {
						//如果签到时间大于最后一次的排期时间表示可以延后的时间段
						if (signDate > Convert.toInt(yyyyMMdd3)) {
							planAndSignDateVo.setIsSelect(selectType);
						}
					}

				}
			} else {
				//非年审
				final Integer signDate = Convert.toInt(yyyyMMdd1);
				if (auditType.equals(AUDIT_TYPES[1])) {
					//提前
					if (planAndSignDateDTO.getType().equals(type)) {
						if (nowDate <= planDate && nowDate <= signDate) {
							planAndSignDateVo.setIsSelect(selectType);
						}
					} else {
						if (planDate <= signDate) {
							planAndSignDateVo.setIsSelect(selectType);
						}
					}

				} else {
					//年审-延后保养
					if (!planAndSignDateDTO.getType().equals(type)) {
						if (signDate > planDate) {
							planAndSignDateVo.setIsSelect(selectType);
						}
					}
				}
			}

			String planId = planAndSignDateVo.getPlanId();
			if (StrUtil.isNotEmpty(planId)&&planId.split(",").length > 1) {
				planAndSignDateVo.setPlanTypeName("多项任务");
			}
		}
		return planAndSignDates;
	}


	/**
	 * 获取明年的数据
	 *
	 * @param planAndSignDateDTO 查询条件
	 * @return 数据集
	 */
	@Override
	public List<PlanAndSignDateVo> getNextYear(PlanAndSignDateDTO planAndSignDateDTO) {
		List<PlanAndSignDateVo> nextYear = baseMapper.getNextYear(planAndSignDateDTO);
		final Map<Integer, List<PlanAndSignDateVo>> listMap = nextYear.stream().collect(Collectors.groupingBy(PlanAndSignDateVo::getPlanDate));
		List<PlanAndSignDateVo> list = new ArrayList<>(16);
		DateTime dateTime = DateUtil.parse(planAndSignDateDTO.getBeginTime() + "", "yyyyMMdd");
		DateTime endTime = DateUtil.parse(planAndSignDateDTO.getEndTime() + "", "yyyyMMdd");
		final Integer days = Convert.toInt(DateUtil.betweenDay(dateTime, endTime, true)) + 1;
		for (int i = 0; i < days; i++) {
			DateTime offsetDay = DateUtil.offsetDay(dateTime, i);
			Integer planDate = Convert.toInt(DateUtil.format(offsetDay, "yyyyMMdd"));
			final List<PlanAndSignDateVo> planAndSignDateVos = listMap.get(planDate);
			if (planAndSignDateVos == null || planAndSignDateVos.size() == 0) {
				PlanAndSignDateVo planAndSignDateVo = new PlanAndSignDateVo();
				planAndSignDateVo.setSignDate(offsetDay);
				list.add(planAndSignDateVo);
			} else {
				list.add(planAndSignDateVos.get(0));
			}
		}
		return list;
	}


}
